package com.sharding.order.service.user.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sharding.order.bean.request.order.UserOrderInfoRequest;
import com.sharding.order.common.enums.OrderEnums;
import com.sharding.order.common.enums.OrderOperateType;
import com.sharding.order.common.enums.RequestSource;
import com.sharding.order.common.mq.RocketMQProducer;
import com.sharding.order.common.util.RedisUtils;
import com.sharding.order.constant.OrderConstant;
import com.sharding.order.context.utils.GenerateOrderNoUtils;
import com.sharding.order.domain.convertor.OrderConvertor;
import com.sharding.order.domain.entity.OrderInfo;
import com.sharding.order.domain.entity.OrderItemDetail;
import com.sharding.order.domain.message.OrderSyncMessage;
import com.sharding.order.domain.query.OrderInfoBaseQuery;
import com.sharding.order.domain.query.UserOrderInfoQuery;
import com.sharding.order.domain.valid.OrderValidation;
import com.sharding.order.domain.vo.OrderInfoVO;
import com.sharding.order.domain.vo.OrderDetailVO;
import com.sharding.order.domain.vo.UserOrderVO;
import com.sharding.order.repository.UserOrderRepository;
import com.sharding.order.service.user.UserOrderInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author ruyuan
 * 用户订单服务实现
 */
@Slf4j
@Service
public class UserOrderInfoServiceImpl implements UserOrderInfoService {

    @Autowired
    private UserOrderRepository userOrderRepository;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private OrderConvertor orderConvertor;
    @Value(value = "${order.topic}")
    private String topic;
    @Autowired
    private RocketMQProducer rocketMQProducer;



    @Override
    public void generateOrder(UserOrderInfoRequest userOrderInfoRequest) {
        //1.入参校验
        OrderValidation.checkVerifyOrderRequest(userOrderInfoRequest);
        //2.添加订单信息
        OrderInfo orderInfo = orderConvertor.dtoConvertOrderInfo(userOrderInfoRequest);
        //3.添加订单详情
        List<OrderItemDetail> orderItemDetailList = userOrderInfoRequest.getOrderItemDetailList();
        //4.生成订单号
        String orderNo = GenerateOrderNoUtils.getOrderNo(orderInfo.getUserId(),orderInfo.getMerchantId());
        //5.为订单和订单明细设置订单号
        orderInfo.setOrderNo(orderNo);
        orderItemDetailList.forEach(orderItemDetail -> orderItemDetail.setOrderNo(orderInfo.getOrderNo()));
        //6.保存订单信息
        userOrderRepository.generateOrderInfo(orderInfo, orderItemDetailList);
        //7.构建消息体
        OrderSyncMessage orderSyncMessage = OrderSyncMessage.builder()
                .requestSource(RequestSource.C)
                .orderOperateType(OrderOperateType.add)
                .orderNo(orderInfo.getOrderNo())
                .build();
        //8.发送mq消息
        rocketMQProducer.reliablySend(topic, orderSyncMessage, orderSyncMessage.getOrderNo(), obj -> {
            OrderSyncMessage message = (OrderSyncMessage) obj;
            // 这里可以将消息存储到db，然后由后台线程定时重试，确保消息一定到达Broker
            log.info("generateOrder send mq message failed, store the mq message to db，orderNo:[{}],message:[{}]",message.getOrderNo(),message);
        });
        //9.设置redis
        redisUtils.set(OrderConstant.OrderRedisKey.PREFIX_KEY + orderInfo.getOrderNo(), orderInfo.getOrderNo(), 900L, TimeUnit.SECONDS);
    }

    /**
     * 根据用户id获得订单列表
     *
     * @param userOrderInfoQuery 入参
     * @return 出参
     */
    @Override
    public Page<UserOrderVO> queryUserOrderInfoList(UserOrderInfoQuery userOrderInfoQuery) {
        //1.入参校验
        OrderValidation.checkVerifyOrderQuery(userOrderInfoQuery);
        //2.转换入参
        OrderInfoBaseQuery orderInfoBaseQuery = orderConvertor.userQueryToBaseOrder(userOrderInfoQuery);
        //3.查询已完成的订单
        if (OrderEnums.COMPLETED.getCode().equals(userOrderInfoQuery.getOrderStatus())) {
            //4.组装redisKey
            String redisKey = userOrderInfoQuery.getUserId() + userOrderInfoQuery.getPageNo().toString() + userOrderInfoQuery.getPageSize().toString();
            //5.获取redis缓存
            Object redisObject = redisUtils.get(redisKey);
            //6.redis为空则从数据库中查询
            if (Objects.isNull(redisObject)) {
                //7.查询订单列表
                Page<OrderInfoVO> orderInfoVOPage = userOrderRepository.queryOrderInfoList(orderInfoBaseQuery);
                //8.转换出参
                Page<UserOrderVO> userOrderVOPage = orderConvertor.OrderVoToUserInfoVo(orderInfoVOPage);
                //9.设置redis缓存，过期时间为一小时
                redisUtils.set(redisKey, userOrderVOPage, 3600L, TimeUnit.SECONDS);
                return userOrderVOPage;
            }
            log.info("get data from redis，key:[{}]",redisKey);
            return (Page<UserOrderVO>) redisObject;
        }
        return orderConvertor.OrderVoToUserInfoVo(userOrderRepository.queryOrderInfoList(orderInfoBaseQuery));
    }

    /**
     * 获取订单详情
     *
     * @param orderNo
     * @return
     */
    @Override
    public OrderDetailVO getOrderDetail(String orderNo) {
        return userOrderRepository.getOrderDetail(orderNo);
    }


    @Override
    public void cancelOrder(String orderNo) {
        userOrderRepository.cancelOrder(orderNo, OrderEnums.CANCEL_ORDER.getCode());
        //构建消息体
        OrderSyncMessage orderSyncMessage = OrderSyncMessage.builder()
                .requestSource(RequestSource.C)
                .orderOperateType(OrderOperateType.updateOrderStatus)
                .orderNo(orderNo)
                .build();
        //发送mq消息
        rocketMQProducer.reliablySend(topic, orderSyncMessage, orderSyncMessage.getOrderNo(), obj -> {
            OrderSyncMessage message = (OrderSyncMessage) obj;
            // 这里可以将消息存储到db，然后由后台线程定时重试，确保消息一定到达Broker
            log.info("cancelOrder send mq message failed, store the mq message to db，orderNo:[{}],message:[{}]",message.getOrderNo(),message);
        });
    }


    @Override
    public void redisCancelOrder(String orderNo) {
        //1.查询订单状态
        Integer orderStatus = userOrderRepository.getOrderStatus(orderNo);
        //2.判断订单状态是否仍未支付
        if (OrderEnums.PENDING_PAYMENT.getCode().equals(orderStatus)) {
            //3.修改订单状态
            userOrderRepository.cancelOrder(orderNo, OrderConstant.OrderBaseStatus.CANCEL_ORDER);
        }
    }


}
